import React, { useRef, useEffect, useState, useImperativeHandle } from "react";
import { Select, Space, Input, message, Button, Form, List, Row, Col } from 'antd';
import { CmdbContent, CmdbHeader, useModelAssociateType} from "@/components";
import { Resizable } from 'react-resizable';
// import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
import cmdbres from "@/data/cmdbres";
import request from "@/utils/request";
import hcpUtils from "@/utils/hcpUtils";
import "./index.less"
import G6 from '@antv/g6';
import registerEdge from './config/register-edge';
import registerNode from './config/register-node';
import { G6ToolBar, G6Menu, G6Legend } from './config/register-plugins';
import { defaultNodeConfig, defaultEdgeConfig, defaultLayout } from "./config/default";
import { initData } from "./config/utils";
import { nodeMouseFn, getIcons } from "@/modules/topology/utils";
import HelpTipModal from './components/helpTipModal';
import DetailsModal from '../components/detailsModal';
import CreateRelation from '../components/createRelation';
import EditRelation from '../components/editRelation';
import DeleteRelation from '../components/deleteRelation';
const GRAPH_ID = "model-graph-container";
// import mockData from './mock.json';

const EditModelTopology = ({ history, match, location }) => {
    const [leftWidth, setLeftWidth] = useState(200);
    const cmModuleId = match.params.id;
    const modelInfo =  location.state;
    const domRef = useRef(null);
    const graphRef = useRef(null)
    let graph = graphRef.current;
    const [showHelp, setShowHelp] = useState(false);
    const [detailInfo, setDetailInfo] = useState({});
    const [showDetailModal, setShowDetailModal] = useState(false);
    const [showCreateRelation, setShowCreateRelation] = useState(false);
    const [showEditRelation, setShowEditRelation] = useState(false);
    const [showDeleteRelation, setShowDeleteRelation] = useState(false);
    const [{associateType}, loading] = useModelAssociateType(); // 翻译关联关系
    const [topoData, setTopoData] = useState();

    const [curEdge, setCurEdge ] = useState(null);
    const [level, setLevel] = useState(1);
    const [dragNodes, setDragNodes] = useState([]);

    const [targetData, setTargetData] = useState([]);// 目标模型数据
    const [newEdge, setNewEdge] = useState();// 新增的边


    useEffect(() => {
      if(modelInfo) {
        fetchData();
      }
    }, [modelInfo, level]);

    const fetchData = async() => {
      const fn = [queryModel()];
      if(modelInfo.moduleCode == "biz") {
        fn.push(queryMainLine());
      } else {
        fn.push(queryAllModelAssociate());
      }
      const [nodes, edges] = await Promise.all(fn);
        if(nodes && edges) {
          getDragNodes(nodes, edges);
          setTopoData({nodes: edges, edges});
        }
    };

    const getDragNodes = (nodes, edges) => {
      let arr = [];
      let set = new Set();
      if(modelInfo?.cmModuleId) {
        set.add(modelInfo.cmModuleId);
      }
      edges?.map(item=> {
        if(item.srcModuleId) set.add(item.srcModuleId);
        if(item.destModuleId) set.add(item.destModuleId);
      })
      hcpUtils.treeDataIteration(nodes, function(item) {
        if(item.definitions) {
          item.definitions.map(m=> {
            if(m.cmModuleId && !set.has(m.cmModuleId)) {
              arr.push({
                ...m,
                listIndex: arr.length
              });
            }
          })
        }
      })
      setDragNodes(arr);
    }

    const queryModel = async () => {
        try {
            let res = await request({
                ...cmdbres.queryModelList,
                params: {
                    namespace: "default"
                },
            });
            return res && res.data ? res.data : [];
        } catch (error) {
          return [];
        }
    };

    const queryAllModelAssociate = async () => {
      try {
          const res = await request({
              ...cmdbres.queryModelAssociate(modelInfo.cmModuleId, level),
              params: {
                pageSize: Number.MAX_SAFE_INTEGER,
                pageNumber: 1,
                sort: {
                  create_time:"DESC"
                }
            },
          });
          return res && res.data ? res.data : [];
      } catch (error) {
          return [];
      }
    };
    //查询拓扑组成的模型关系
    const queryMainLine = async () => {
        try {
            const res = await request({
                ...cmdbres.queryMainLine,
                params: {},
            });
            let arr = [];
            if(res && res.data) {
              res.data.map(item=> {
                if(item.nextModuleId) {
                  arr.push({
                    srcModuleId: item.nextModuleId,
                    srcModuleCode: item.nextModuleCode,
                    srcModuleName: item.nextModuleName,
                    destModuleId: item.moduleId,
                    destModuleCode: item.moduleCode,
                    destModuleName: item.moduleName,
                    associateType: '拓扑组成'
                  })
                }
              })
            }
            return arr
        } catch (error) {
            console.log(error);
        }
    };

    useEffect(() => {
      if(!(associateType && topoData)) return;
      const data = initData(topoData, associateType, modelInfo);
      graph = createGraphic();
      graph.read(data);
      // 关闭局部渲染解决缩放或者拖拽引起的残影问题（关闭会影响性能，临时解决办法）
      graph.get('canvas').set('localRefresh', false);
      bindEvents();

      return () => {
        if(graph) {
          graph.destroy();
        }
      };
    },[associateType, topoData])

    const createGraphic = () => {
        // 注册自定义节点
        registerEdge(G6);
        // 注册自定义边
        registerNode(G6);

        const container = document.getElementById(GRAPH_ID);
        const tree = new G6.Graph({
          container: domRef.current,
          width: container.offsetWidth,
          height: container.offsetHeight,
          fitCenter: true,
          defaultNode: defaultNodeConfig,
          defaultEdge: defaultEdgeConfig,
          layout: defaultLayout,
          animate: true,
          modes: {
            default: [
              'drag-canvas',
              'drag-node',
              'zoom-canvas',
              {
                type: 'create-edge',
                shouldBegin: (e) => {
                  const model = e.item && e.item.getModel()
                  //除中心节点和新增节点，其他节点不允许操作
                  if (model && (model.isRoot)) {
                    return true
                  } else {
                    return false;
                  };
                },
                shouldEnd: (e) => {
                  const model = e.item && e.item.getModel();
                  //除中心节点和新增节点，其他节点不允许操作
                  let flag = false;
                  if (model && model.isNewNode) {
                    flag = true;
                  }
                  return flag;
                },
              }
            ],
          },
          plugins: [
            new G6.Grid(),
            new G6.Minimap({
              size: [200, 150],
            }),
            G6Menu(G6, menuHandles, true),
            G6ToolBar(G6, setShowHelp),
          ],
        });

        graphRef.current = tree;
        return tree;
    };

    const bindEvents = () => {
      graph.on('node:mouseenter', (evt)=> nodeMouseFn(evt, true, graph));
      graph.on('node:mouseleave', (evt)=> nodeMouseFn(evt, false, graph));

      graph.on('edge:mouseenter', (evt) => {
        const edge = evt.item;
        graph.setItemState(edge, 'hover', true);
      });

      graph.on('edge:mouseleave', (evt) => {
          const edge = evt.item;
          graph.setItemState(edge, 'hover', false);
      });
      graph.on('canvas:click', (evt) => {
        graph.getNodes().forEach((node) => {
          graph.clearItemStates(node);
        });
      });
      graph.on('edge:click', (evt)=> {
        const {item} = evt;
        if(item.destroyed) return true;
        const model = item.getModel();
        if(model) {
          setCurEdge(model);
          setShowEditRelation(true);
        }
      });
      graph.on('aftercreateedge', ({edge})=> {
        if(edge) {
          const model = edge.getModel();
          if(model) {
            const source = edge.getSource().getModel();
            const target = edge.getTarget().getModel();
            setDetailInfo(source);
            setTargetData([target]);
            // if(source.moduleId == target.moduleId) {
            //   graph.removeItem(edge, false);
            //   return;
            // }
            // if(source.isRoot) {
            //   setDetailInfo(source);
            //   setTargetData([target]);
            // } else {
            //   setDetailInfo(target);
            //   setTargetData([source]);
            // }
            setShowCreateRelation(true);
            setNewEdge(edge);
          }
        }
      })

    }
    const menuHandles = {
      queryDetail(item) {
        const model = item.getModel();
        setDetailInfo(model);
        setShowDetailModal(true);
      },
      addNode(item) {
        const model = item.getModel();
        setDetailInfo(model);
        setTargetData(dragNodes);
        setShowCreateRelation(true);
      },
      deleteNode(item) {
        const model = item.getModel();
        const edges = item.getEdges();
        if(!model || (model && model.isRoot)) {// 点击中心节点，不删除关联
          return;
        }
        if(model && edges) {
          const edge = edges.find(e=> {// 查找与中心节点的关联
            const m = e.getModel();
            if(m.srcModuleId == modelInfo.cmModuleId || m.destModuleId == modelInfo.cmModuleId) {
              return e;
            }
          });
          if(edge) {
            setCurEdge(edge.getModel());
            setShowDeleteRelation(true);
          } else {
            setDragNodes(dragNodes=> {
              let arr = JSON.parse(JSON.stringify(dragNodes))
              arr.splice(model.listIndex, 0, model);
              return arr;
            })
            graph.removeItem(item);
          }
        }
      }
    };

    const ondragstart = (e, item) => {
      e.dataTransfer.setData("dragModel", JSON.stringify(item));
    }
    const ondragover = (e) => {
      e.preventDefault();
    }
    const ondrop = (e) => {
      e.preventDefault();
      // console.log(e)
      let node = e.dataTransfer.getData("dragModel");
      if(node) {
        node = JSON.parse(node);
        setDragNodes(dragNodes=> {
          const arr = dragNodes.filter(m=> m.cmModuleId != node.cmModuleId);
          return arr;
        })

        const point = graph.getPointByClient(e.clientX, e.clientY);

        const { cmModuleId, moduleCode, moduleIcon, moduleName} = node;
        graph.addItem('node', {
            ...node,
            type: 'rect-node',
            id: cmModuleId,
            label: moduleName,
            x: point.x,
            y: point.y,
            moduleId: cmModuleId,
            moduleName: moduleName,
            moduleCode: moduleCode,
            icon: getIcons(moduleIcon),
            isNewNode: true, //插入的新节点
        })
        graph.layout();
      }
    }
    return (
      <CmdbContent>
            <CmdbHeader
              title={`编辑【${modelInfo?.moduleName??''}】模型拓扑`}
              showBackButton
              history={history}
              goBackUrl={`/model/topology/`}
              goBackUrlState={modelInfo}
              subTitle={"所有更改自动保存"}
            />
            <section className="hcp__page">
                <section className="hcp__page__container model-graph-group">
                    <div className="main-views">
                        <Resizable
                            width={leftWidth}
                            axis='x'
                            height={0}
                            minConstraints={[200]}
                            maxConstraints={[400]}
                            handle={React.createElement('span', {
                                className: `react-resizable-handle`,
                                onClick: (e) => {
                                    e.stopPropagation();
                                },
                            })}
                            onResize={(event, { element, size })=> {setLeftWidth(size.width);}}
                            draggableOpts={{ enableUserSelectHack: false }}
                        >
                            <div style={{width: leftWidth, height:'100%', float: 'left', marginRight: 10, background: 'white', overflow: 'auto'}}>
                              <Row className="drag-box">
                                {dragNodes.map((item, index)=> (
                                  <Col
                                    key={item.cmModuleId}
                                    span={12}
                                    className="drag-item"
                                    draggable="true"
                                    onDragStart={(e)=> {ondragstart(e, item)}}
                                  >
                                    <div className="drag-icon">
                                      <div className={`iconfont ${item.moduleIcon}`}></div>
                                    </div>
                                    <div className="name">{item.listIndex}-{item.moduleName}</div>
                                  </Col>
                                ))}
                              </Row>
                            </div>
                        </Resizable>
                        <div
                          style={{width: `calc(100% - ${leftWidth}px - 10px)`}} className="right-content"
                          onDragOver={ondragover}
                          onDrop={ondrop}
                        >
                          <div style={{ width: '100%', height: 710, position: 'relative' }}>
                            <div ref={domRef} id={GRAPH_ID} style={{ width: '100%', height: 'calc(100% - 74px)'}} ></div>
                        </div>
                        </div>
                        <HelpTipModal visible={showHelp} setVisible={setShowHelp}/>
                        <DetailsModal visible={showDetailModal} setVisible={setShowDetailModal} info={detailInfo}/>
                        {showCreateRelation&&<CreateRelation
                            onCreateFinish={(flag)=>{
                              if(flag) {
                                fetchData();
                              } else {
                                if(newEdge) {
                                  graph.removeItem(newEdge);
                                  setNewEdge();
                                }
                              }
                            }}
                            visible={showCreateRelation}
                            setVisible={setShowCreateRelation}
                            info={detailInfo}
                            targetData={targetData}
                        />}
                        {showEditRelation&&<EditRelation
                            onCreateFinish={()=>{fetchData()}}
                            visible={showEditRelation}
                            setVisible={setShowEditRelation}
                            info={curEdge}
                        />}
                        <DeleteRelation
                            onDeleteFinish={()=>{fetchData()}}
                            visible={showDeleteRelation}
                            setVisible={setShowDeleteRelation}
                            info={curEdge}
                        />
                    </div>
                </section>
            </section>
        </CmdbContent>
    )
}

export default EditModelTopology;


